home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / telecomm / sticpsrc.lzh / SOURCE.ARC / SMTPCLI.C < prev    next >
C/C++ Source or Header  |  1990-08-10  |  26KB  |  1,099 lines

  1. /*
  2.  *    Client routines for Simple Mail Transfer Protocol ala RFC821
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *    Modified 14 June 1987 by P. Karn for symbolic target addresses,
  8.  *    also rebuilt locking mechanism
  9.  *    Limit on max simultaneous sessions, reuse of connections - 12/87 NN2Z
  10.  *    Added return of mail to sender as well as batching of commands 1/88 nn2z
  11.  */
  12.  
  13. #include <stdio.h>
  14. #ifndef ATARI_ST
  15. #include <fcntl.h>
  16. #endif
  17. #include <time.h>
  18. #ifdef UNIX
  19. #include <sys/types.h>
  20. #endif
  21. #include "global.h"
  22. #include "config.h"
  23. #include "netuser.h"
  24. #include "mbuf.h"
  25. #include "timer.h"
  26. #include "tcp.h"
  27. #include "smtp.h"
  28. #include "trace.h"
  29. #include "cmdparse.h"
  30.  
  31. extern int16 lport;            /* local port */
  32. extern int32 resolve();
  33. static struct timer smtpcli_t;        /* client startup timer */
  34. static int32 queuetime = SEC2TICK(500); /* kicktime for queued mail */
  35. int32 gateway;
  36.  
  37. #ifdef SMTPTRACE
  38. int16    smtptrace = 0;            /* used for trace level */
  39. int dosmtptrace();
  40. #endif
  41.  
  42. int16    smtpmaxcli  = MAXSESSIONS;    /* the max client connections allowed */
  43. int16    smtpsessions = 0;        /* number of client connections
  44.                      * currently open */
  45. int16    smtpmode = 0;
  46.  
  47. static struct smtp_cb *cli_session[MAXSESSIONS]; /* queue of client sessions  */
  48.  
  49. static char helocmd[] = "HELO %s\r\nMAIL FROM:<%s>\r\n";
  50. static char mailcmd[] = "MAIL FROM:<%s>\r\n";
  51. static char rcptcmd[] = "RCPT TO:<%s>\r\n";
  52. static char datacmd[] = "DATA\r\n";
  53. static char rsetcmd[] = "RSET\r\n";
  54. static char quitcmd[] = "QUIT\r\n";
  55. static char eom[] = "\r\n.\r\n";
  56.  
  57. static int smtptick(),dogateway(),dosmtpmaxcli(),dotimer();
  58. static int setsmtpmode(),sendwindow();
  59. static void quit(),abort_trans(),sendit(),del_job();
  60. static void execjobs(),smtp_transaction();
  61. static struct smtp_cb *newcb(),*lookup();
  62. static struct smtp_job *setupjob();
  63. void del_session(),logerr(),retmail();
  64. int mlock(),rmlock(),nextjob();
  65. extern void mbxfwd();
  66.  
  67. extern char *getnenv();
  68.  
  69. #if (defined(ATARI_ST) && defined(__TURBOC__))
  70. static void sendit(struct smtp_cb *,char *,...);
  71. #endif
  72.  
  73. struct cmds smtpcmds[] = {
  74.     "gateway",    dogateway,    0,    NULLCHAR,    NULLCHAR,
  75.     "mode",        setsmtpmode,    0,    NULLCHAR,    NULLCHAR,
  76.     "kick",        smtptick,    0,    NULLCHAR,    NULLCHAR,
  77.     "maxclients",    dosmtpmaxcli,    0,    NULLCHAR,    NULLCHAR,
  78.     "timer",    dotimer,    0,    NULLCHAR,    NULLCHAR,
  79. #ifdef SMTPTRACE
  80.     "trace",    dosmtptrace,    0,    NULLCHAR,    NULLCHAR,
  81. #endif
  82.     NULLCHAR,    NULLFP,        0,
  83.     "?subcommands",
  84.         NULLCHAR
  85. };
  86.  
  87. dosmtp(argc,argv)
  88. int argc;
  89. char *argv[];
  90. {
  91.     return subcmd(smtpcmds,argc,argv);
  92. }
  93.  
  94. static int
  95. dosmtpmaxcli(argc,argv)
  96. int argc;
  97. char *argv[];
  98. {
  99.     int x;
  100.     if (argc < 2)
  101.         printf("%d\n",smtpmaxcli);
  102.     else {
  103.         x = atoi(argv[1]);
  104.         if (x > MAXSESSIONS)
  105.             printf("max clients must be <= %d\n",MAXSESSIONS);
  106.         else
  107.             smtpmaxcli = x;
  108.     }
  109.     return 0;
  110. }
  111.  
  112. static int
  113. setsmtpmode(argc,argv)
  114. int argc;
  115. char *argv[];
  116. {
  117.     if (argc < 2) {
  118.         printf("smtp mode: %s\n",
  119.             (smtpmode & QUEUE) ? "queue" : "route");
  120.     } else {
  121.         switch(*argv[1]) {
  122.         case 'q':
  123.             smtpmode |= QUEUE;
  124.             break;
  125.         case 'r':
  126.             smtpmode &= ~QUEUE;
  127.             break;
  128.         default:
  129.             printf("Usage: smtp mode [queue | route]\n");
  130.             break;
  131.         }
  132.     }
  133.     return 0;
  134. }
  135. static int
  136. dogateway(argc,argv)
  137. int argc;
  138. char *argv[];
  139. {
  140.     extern char badhost[];
  141.  
  142.     if(argc < 2){
  143.         printf("%s\n",inet_ntoa(gateway));
  144.     } else if((gateway = resolve(argv[1])) == 0 && argv[1][0] != '['){
  145.         printf(badhost,argv[1]);
  146.         return 1;
  147.     }
  148.     return 0;
  149. }
  150.  
  151. #ifdef SMTPTRACE
  152. static int
  153. dosmtptrace(argc,argv)
  154. int argc;
  155. char *argv[];
  156. {
  157.     if (argc < 2)
  158.         printf("%d\n",smtptrace);
  159.     else
  160.         smtptrace = atoi(argv[1]);
  161.     return 0;
  162. }
  163. #endif
  164.  
  165. /* Set outbound spool poll interval */
  166. static int
  167. dotimer(argc,argv)
  168. int argc;
  169. char *argv[];
  170. {
  171.     if(argc < 2){
  172.         printf("%lu/%lu (%lu)\n",TICK2SEC(smtpcli_t.start - smtpcli_t.count),
  173.                      TICK2SEC(smtpcli_t.start),
  174.                      TICK2SEC(queuetime));
  175.         return 0;
  176.     }
  177.     stop_timer(&smtpcli_t);
  178.     smtpcli_t.func = (void (*)())smtptick;    /* what to call on timeout */
  179.     smtpcli_t.start = SEC2TICK(atol(argv[1])); /* set timer duration */
  180.     start_timer(&smtpcli_t);        /* and fire it up */
  181.     if (argc > 2)                /* queuetime specified? */
  182.         queuetime = SEC2TICK(atol(argv[2]));
  183.     return 0;
  184. }
  185. /* kick the timer when a job is queued */
  186. void
  187. queuekick()
  188. {
  189.     int32 savedstart;
  190.  
  191.     if (queuetime == 0)            /* no queue'd job kick? */
  192.         return;
  193.  
  194.     savedstart = smtpcli_t.start;        /* keep normal smtp timer */
  195.     stop_timer(&smtpcli_t);
  196.     smtpcli_t.func = (void (*)())smtptick;
  197.     smtpcli_t.start = queuetime;        /* set temporary timer value */
  198.     start_timer(&smtpcli_t);        /* and fire it up */
  199.     smtpcli_t.start = savedstart;        /* restore full time value */
  200. }
  201.  
  202. /* this is the routine that gets called every so often to do outgoing mail
  203.    processing */
  204. static int
  205. smtptick()
  206. {
  207.     register struct smtp_cb *cb;
  208.     struct smtp_job *jp;
  209. #ifdef SMTPTRACE
  210.     struct list *ap;
  211. #endif
  212.     char    *mailqdir;
  213.     char    *cp, *cp1;
  214.     int32    destaddr;
  215.     FILE    *wfile;
  216.     char    sysname[LINELEN], tmpstring[LINELEN];
  217.     char    wfilename[13], prefix[9];
  218.     char    mailq[80];
  219.  
  220. #ifdef SMTPTRACE
  221.     if (smtptrace > 5) {
  222.         printf("smtp daemon entered\n");
  223.         fflush(stdout);
  224.     }
  225. #endif
  226.     strcpy(mailq,mailqdir = getnenv(MAILQDIR));
  227.     strcat(mailq,mailqueue);
  228.     for(filedir(mailq,0,wfilename);wfilename[0] != '\0';
  229.         filedir(mailq,1,wfilename)){
  230.  
  231.         /* save the prefix of the file name which it job id */
  232.         cp = wfilename;
  233.         cp1 = prefix;
  234.         while (*cp && *cp != '.')
  235.             *cp1++ = *cp++;
  236.         *cp1 = '\0';
  237.  
  238.         /* lock this file from the smtp daemon */
  239.         if (mlock(mailqdir,prefix))
  240.             continue;
  241.  
  242.         sprintf(tmpstring,"%s%s",mailqdir,wfilename);
  243.         if ((wfile = fopen(tmpstring,"r")) == NULLFILE) {
  244.             /* probably too many open files */
  245.             rmlock(mailqdir,prefix);
  246.             /* continue to next message. The failure
  247.              * may be temporary */
  248.             continue;
  249.         }
  250.  
  251.         fgets(sysname,LINELEN,wfile);    /* read target host */
  252.         rip(sysname);
  253.  
  254.         if ((destaddr = mailroute(sysname)) == 0) {
  255.             fclose(wfile);
  256.             printf("** smtp: Unknown address %s\n",sysname);
  257.             fflush(stdout);
  258.             continue;
  259.         }
  260.  
  261.         if ((cb = lookup(destaddr)) == NULLCB) {
  262.             /* there are enough processes running already */
  263.             if (smtpsessions >= smtpmaxcli) {
  264. #ifdef SMTPTRACE
  265.                 if (smtptrace) {
  266.                     printf("smtp daemon: too many processes\n");
  267.                     fflush(stdout);
  268.                 }
  269. #endif
  270.                 fclose(wfile);
  271.                 rmlock(mailqdir,prefix);
  272.                 continue;
  273.             }
  274.             if ((cb = newcb(tmpstring)) == NULLCB) {
  275.                 fclose(wfile);
  276.                 rmlock(mailqdir,prefix);
  277.                 continue;
  278.             }
  279.             cb->ipdest = destaddr;
  280.         } else {
  281.             /* This system already is sending mail lets not
  282.             * interfere with it's send queue.
  283.             */
  284.             if (cb->state != CLI_INIT_STATE && cb->state != CLI_OPEN_STATE) {
  285.                 fclose(wfile);
  286.                 rmlock(mailqdir,prefix);
  287.                 continue;
  288.             }
  289.         }
  290.  
  291.         fgets(tmpstring,LINELEN,wfile); /* read from */
  292.         rip(tmpstring);
  293.         if ((jp = setupjob(cb,prefix,sysname,tmpstring)) == NULLJOB) {
  294.             fclose(wfile);
  295.             rmlock(mailqdir,prefix);
  296.             del_session(cb);
  297.             continue;
  298.         }
  299.         while (fgets(tmpstring,LINELEN,wfile) != NULLCHAR) {
  300.             rip(tmpstring);
  301.             if (addlist(&jp->to,tmpstring,DOMAIN) == NULLLIST) {
  302.                 fclose(wfile);
  303.                 del_session(cb);
  304.             }
  305.         }
  306.         fclose(wfile);
  307. #ifdef SMTPTRACE
  308.         if (smtptrace > 1) {
  309.             printf("queue job %s From: %s To:",prefix,from);
  310.             for (ap = jp->to; ap != NULLLIST; ap = ap->next)
  311.                 printf(" %s",ap->val);
  312.             printf("\n");
  313.             fflush(stdout);
  314.         }
  315. #endif
  316.     }
  317.  
  318.     /* start sending that mail */
  319.     execjobs();
  320.  
  321.     /* Restart timer */
  322.     start_timer(&smtpcli_t);
  323. }
  324.  
  325. /* this is the master state machine that handles a single SMTP transaction */
  326. static void
  327. smtp_transaction(cb)
  328. register struct smtp_cb *cb;
  329. {
  330.     void smtp_cts();
  331.     register char reply;
  332.     register struct list *tp;
  333.     int cnt;
  334.     struct mbuf *bp,*bpl;
  335.     char tbuf[LINELEN];
  336.     int rcode;
  337.  
  338. #ifdef SMTPTRACE
  339.     if (smtptrace > 5)
  340.         printf("smtp_transaction() enter state=%u\n",cb->state);
  341.     if (s